using UnityEngine;
using UnityEngine.UI;
using System;
using System.Collections.Generic;
using System.Text;

public class CentralNordicScript : MonoBehaviour
{
	public Transform PanelCentral;
	public Text Name;
	public Text Address;
	public Text Receive;
    public Text Trick;
	//public InputField Send;
	public Text TextConnectButton;
	public GameObject SendButton;
    public GameObject skateboard;
    public float currAlt = 0.0F;
    public float kickFlipAngles = 0.0F;
    public float heelFlipAngles = 0.0F;
    public float backsideAngles = 0.0F;
    public float frontsideAngles = 0.0F;
    public float oldRoll = 0.0F;
    public float oldYaw = 0.0F;
    public bool initial = true;
    public bool isBack180 = false;
    public bool isFront180 = false;
    private bool _initializeError = false;
    private string _inputText = "\n\n\n\n";
    private int _speechId = 0;
    private float _pitch = 1f, _speechRate = 1f;
    private int _selectedLocale = 0;
    private string[] _localeStrings;

    private bool _connecting = false;
	private string _connectedID = null;
	private string _serviceUUID = "0001";
	private string _readCharacteristicUUID = "0003";
	private string _writeCharacteristicUUID = "0002";
	private float _subscribingTimeout = 0f;
	private bool _readFound = false;
	private bool _writeFound = false;
    public DateTime lastTrick = DateTime.Now;

	bool _connected = false;
	bool Connected
	{
		get { return _connected; }
		set
		{
			_connected = value;
			
			if (_connected)
			{
				TextConnectButton.text = "Disconnect";
				_connecting = false;
			}
			else
			{
				TextConnectButton.text = "Connect";
				_connectedID = null;
				Receive.text = "";
				//Send.text = "";
				SendButton.SetActive (false);
			}
		}
	}
	
	public void Initialize (CentralPeripheralButtonScript centralPeripheralButtonScript)
	{
        TTSManager.Initialize("skateboard", "OnTTSInit");
        //TTSManager.SetLanguage(TTSManager.GetAvailableLanguages()[0]);
		Connected = false;
		Name.text = centralPeripheralButtonScript.TextName.text;
		Address.text = centralPeripheralButtonScript.TextAddress.text;
		Receive.text = "";
		//Send.text = "";
	}
	
	void disconnect (Action<string> action)
	{
		BluetoothLEHardwareInterface.DisconnectPeripheral (Address.text, action);
	}

	/*public void OnSend ()
	{
		if (Send.text.Length > 0)
		{
			byte[] bytes = ASCIIEncoding.UTF8.GetBytes (Send.text);
			if (bytes.Length > 0)
				SendBytes (bytes);

			//Send.text = "";
		}
	}*/

	public void OnBack ()
	{
		if (Connected)
		{
			disconnect ((Address) => {
				
				Connected = false;
                //GameObject skateboard = GameObject.Find("Skateboard");
                skateboard.GetComponent<Renderer>().enabled = false;
                BLETestScript.Show (PanelCentral.transform);
			});
		}
		else
			BLETestScript.Show (PanelCentral.transform);
	}
	
	public void OnConnect ()
	{
		if (!_connecting)
		{
			if (Connected)
			{
				disconnect ((Address) => {
					Connected = false;
                    //GameObject skateboard = GameObject.Find("Skateboard");
                    skateboard.GetComponent<Renderer>().enabled = false;
                });
			}
			else
			{
				_readFound = false;
				_writeFound = false;

				BluetoothLEHardwareInterface.ConnectToPeripheral (Address.text, (address) => {
				},
				(address, serviceUUID) => {
				},
				(address, serviceUUID, characteristicUUID) => {
					
					// discovered characteristic
					if (IsEqual(serviceUUID, _serviceUUID))
					{
						_connectedID = address;
						
						Connected = true;

						if (IsEqual (characteristicUUID, _readCharacteristicUUID))
						{
							_readFound = true;
						}
						else if (IsEqual (characteristicUUID, _writeCharacteristicUUID))
						{
							_writeFound = true;
						}
					}
				}, (address) => {
					
					// this will get called when the device disconnects
					// be aware that this will also get called when the disconnect
					// is called above. both methods get call for the same action
					// this is for backwards compatibility
					Connected = false;
				});
                skateboard = GameObject.Find("Skateboard");
                skateboard.GetComponent<Renderer>().enabled = true;
                _connecting = true;
            }
		}
	}

	// Use this for initialization
	void Start ()
	{
	}
	
	// Update is called once per frame
	void Update ()
	{
		if (_readFound && _writeFound)
		{
			_readFound = false;
			_writeFound = false;

			_subscribingTimeout = 1f;
		}

		if (_subscribingTimeout > 0f)
		{
			_subscribingTimeout -= Time.deltaTime;
			if (_subscribingTimeout <= 0f)
			{
				_subscribingTimeout = 0f;

				BluetoothLEHardwareInterface.SubscribeCharacteristicWithDeviceAddress (_connectedID, FullUUID (_serviceUUID), FullUUID (_readCharacteristicUUID), (deviceAddress, notification) => {
					
				}, (deviceAddress2, characteristic, data) => {

					BluetoothLEHardwareInterface.Log ("id: " + _connectedID);
					if (deviceAddress2.CompareTo (_connectedID) == 0)
					{
						BluetoothLEHardwareInterface.Log (string.Format ("data length: {0}", data.Length));
						if (data.Length == 0)
						{
						}
						else
						{
							string s = ASCIIEncoding.UTF8.GetString (data);
							BluetoothLEHardwareInterface.Log ("data: " + s);
							Receive.text = s;
                            string[] receive = s.Split(' ');
                            float yaw = float.Parse(receive[0]);
                            float roll = float.Parse(receive[1]);
                            float pitch = float.Parse(receive[2]);
                            //float altitude = float.Parse(receive[3]);
                            //float temp = float.Parse(receive[4]);
                            //float delta = skateboard.transform.rotation.y - x;
                            TimeSpan diff = DateTime.Now - lastTrick;
                            double seconds = diff.Seconds;
                            if(seconds > 0.5)
                            {
                                if(isFront180)
                                {
                                    TTSManager.Speak("Front One Eighty", false, TTSManager.STREAM.Music, 1f, 0f, null, null, null);
                                }
                                if(isBack180)
                                {
                                    TTSManager.Speak("Back One Eighty", false, TTSManager.STREAM.Music, 1f, 0f, null, null, null);
                                }
                                isFront180 = isBack180 = false;
                            }
                            if (!initial)
                            {
                                KickFlip(roll);
                                HeelFlip(roll);
                                Frontside(yaw);
                                Backside(yaw);
                            }
                            initial = false;
                            //Trick.text = "" + kickFlipAngles + "R: " + roll + "O: " + oldRoll;
                            oldRoll = roll;
                            oldYaw = yaw;
                            skateboard.transform.eulerAngles = new Vector3(pitch, yaw, roll);
                            //skateboard.transform.rotation.y = x;
                            //var rotationVector = skateboard.transform.rotation.eulerAngles;
                            //rotationVector.y = x;
                            //skateboard.transform.rotation = Quaternion.Euler(rotationVector);
                        }
                    }
					
				});
				
				//SendButton.SetActive (true);
			}
		}
	}

    void Trim()
    {
        if (Trick.text.Length > 45)
        {
            int i = Trick.text.LastIndexOf("\n");
            Trick.text = Trick.text.Substring(0, i + 1);
        }
        lastTrick = DateTime.Now;
    }
    void KickFlip(float roll)
    {
        if (roll > 350 || roll < 10)
        {
            kickFlipAngles = 0.0F;
        }
        else {
            float diff = Dist(roll, oldRoll);
            if (diff > 0)
            {
                kickFlipAngles += diff;
                if (kickFlipAngles >= 300)
                {
                    Trim();
                    Trick.text = "KICKFLIP\n"+Trick.text;
                    heelFlipAngles = frontsideAngles = backsideAngles = kickFlipAngles = 0.0F;
                    //isBack180 = isFront180 = false;
                    TTSManager.Speak("Kickflip", false, TTSManager.STREAM.Music, 1f, 0f, null, null, null);
                }
            }
            else
            {
                kickFlipAngles = 0.0F;
            }
        }
    }
    float Dist(float _new, float _old)
    {
        float diff = _new - _old;
        if(diff < -180)
        {
            return diff + 360;
        }
        else if(diff > 180)
        {
            return diff - 360;
        }
        else
        {
            return diff;
        }
        

    }
    void HeelFlip(float roll)
    {
        if (roll > 350 || roll < 10)
        {
            heelFlipAngles = 0.0F;
        }
        else {
            float diff = Dist(roll, oldRoll);
            if (diff < 0)
            {
                heelFlipAngles += diff;
                if (heelFlipAngles <= -300)
                {
                    Trim();
                    Trick.text = "HEELFLIP\n"+Trick.text;
                    heelFlipAngles = frontsideAngles = backsideAngles = kickFlipAngles = 0.0F;
                    //isBack180 = isFront180 = false;
                    TTSManager.Speak("Heelflip", false, TTSManager.STREAM.Music, 1f, 0f, null, null, null);
                }
            }
            else
            {
                heelFlipAngles = 0.0F;
            }
        }
    }

    void Backside(float yaw)
    {
        float diff = Dist(yaw, oldYaw);
        if (diff > 0)
        {
            backsideAngles += diff;
            if (backsideAngles >= 130 && !isBack180)
            {
                isBack180 = true;
                Trim();
                Trick.text = "BACK 180\n"+Trick.text;
                heelFlipAngles = frontsideAngles = kickFlipAngles = 0.0F;
                isFront180 = false;
                //TTSManager.Speak("Back One Eighty", false, TTSManager.STREAM.Music, 1f, 0f, null, null, null);
            }
            if(backsideAngles >= 290)
            {
                isBack180 = false;
                isFront180 = false;
                Trim();
                Trick.text = Trick.text.Substring(Trick.text.IndexOf("\n")+1);
                Trick.text = "BACK 360\n"+Trick.text;
                heelFlipAngles = frontsideAngles = backsideAngles = kickFlipAngles = 0.0F;
                TTSManager.Speak("Back Three Sixty", false, TTSManager.STREAM.Music, 1f, 0f, null, null, null);
            }
        }
        else
        {
            backsideAngles = 0.0F;
        }
    }

    void Frontside(float yaw)
    {
        float diff = Dist(yaw, oldYaw);
        if (diff < 0)
        {
            frontsideAngles += diff;
            if (frontsideAngles <= -130 && !isFront180)
            {
                isFront180 = true;
                Trim();
                Trick.text = "FRONT 180\n"+Trick.text;
                heelFlipAngles = backsideAngles = kickFlipAngles = 0.0F;
                isBack180 = false;
                //TTSManager.Speak("Front One Eighty", false, TTSManager.STREAM.Music, 1f, 0f, null, null, null);
            }
            if (frontsideAngles <= -290)
            {
                isFront180 = false;
                isBack180 = false;
                Trim();
                Trick.text = Trick.text.Substring(Trick.text.IndexOf("\n")+1);
                Trick.text = "FRONT 360\n"+Trick.text;
                TTSManager.Speak("Front Three Sixty", false, TTSManager.STREAM.Music, 1f, 0f, null, null, null);
                heelFlipAngles = frontsideAngles = backsideAngles = kickFlipAngles = 0.0F;
            }
        }
        else
        {
            frontsideAngles = 0.0F;
        }
    }

    void OnDestroy()
    {
        TTSManager.Shutdown();
    }

    void OnTTSInit(string message)
    {
        int response = int.Parse(message);

        switch (response)
        {
            case TTSManager.SUCCESS:
                List<TTSManager.Locale> l = TTSManager.GetAvailableLanguages();
                _localeStrings = new string[l.Count];
                for (int i = 0; i < _localeStrings.Length; ++i)
                    _localeStrings[i] = l[i].Name;

                break;
            case TTSManager.ERROR:
                _initializeError = true;
                break;
        }
    }

    string FullUUID (string uuid)
	{
		return "6E40" + uuid + "-B5A3-F393-E0A9-E50E24DCCA9E";
	}
	
	bool IsEqual(string uuid1, string uuid2)
	{
		if (uuid1.Length == 4)
			uuid1 = FullUUID (uuid1);
		if (uuid2.Length == 4)
			uuid2 = FullUUID (uuid2);

		return (uuid1.ToUpper().CompareTo(uuid2.ToUpper()) == 0);
	}
	
	void SendByte (byte value)
	{
		byte[] data = new byte[] { value };
		BluetoothLEHardwareInterface.WriteCharacteristic (_connectedID, FullUUID (_serviceUUID), FullUUID (_writeCharacteristicUUID), data, data.Length, true, (characteristicUUID) => {
			
			BluetoothLEHardwareInterface.Log ("Write Succeeded");
		});
	}
	
	void SendBytes (byte[] data)
	{
		BluetoothLEHardwareInterface.Log (string.Format ("data length: {0} uuid: {1}", data.Length.ToString (), FullUUID (_writeCharacteristicUUID)));
		BluetoothLEHardwareInterface.WriteCharacteristic (_connectedID, FullUUID (_serviceUUID), FullUUID (_writeCharacteristicUUID), data, data.Length, true, (characteristicUUID) => {

			BluetoothLEHardwareInterface.Log ("Write Succeeded");
		});
	}
}
